package cn.sh.library.mgts.framework.commonparser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;

import cn.sh.library.mgts.common.Constant;

public abstract class QueryParser {
	
	final protected String OPRATE_EQUAL = "EQUAL";
	final protected String OPRATE_COLON = "COLON";
	final protected String OPRATE_NOT_EQUAL = "NOT_EQUAL";
	final protected String OPRATE_NOT_COLON = "NOT_COLON";
	final protected String OPRATE_LESSTHAN = "LESSTHAN";
	final protected String OPRATE_LESSTHANEQ = "LESSTHANEQ";
	final protected String OPRATE_MORETHAN = "MORETHAN";
	final protected String OPRATE_MORETHANEQ = "MORETHANEQ";
	final protected List<String> DOC_TYPE_VALUES = Arrays.asList(new String[] {"P", "D"});
	final protected List<String> LITERATURE_TYPE_VALUES = Arrays.asList(new String[] {"JDBK", "JDTS", "JP", "GJ", "SD", "HSWX"});
	final protected List<String> SEARCH_FIELDS = Arrays.asList(new String[] {"ALL", "TI", "ED", "PP", "IS", "PL", "CO", "HO", 
			"CO.FN", "CO.NA", "CO.NP", "CO.BD", "CO.DD", "CO.OF", "CO.GE", "CO.NT", "CO.TE", 
			"FN", "NA", "NP", "BD", "DD", "OF", "GE", "NT", "TE", "RE", 
			"RE.FN", "RE.NA", "RE.NP", "RE.BD", "RE.DD", "RE.OF", "RE.GE", "RE.NT", "RE.TE", 
			"TM", "CS","SSH", "ZRZ" , "CBD","CBJG", "YEAR" , "ZTC","FXJG" });
	protected Map<String, String> field_map = Constant.EXPR_FIELD_MAP;
	protected QueryBuilder q;
	protected Set<String> types = new HashSet<>();
	protected Set<String> docTypes = new HashSet<>();
//	final String OPRATE_LIKE = "";
	
	protected String getEsField(String key) {
		return this.field_map.getOrDefault(key, key);
	}
	
	protected String getEsFieldKeyword(String key) {
		return this.field_map.getOrDefault(key, key) + ".keyword";
	}
	
	public Set<String> getTypes(){
		if(this.types.size() == 0) {
			return new HashSet<>(DOC_TYPE_VALUES);
		}
		return this.types;
	}
	
	public Set<String> getDocTypes(){
		if(getTypes().contains("D") && this.docTypes.size() == 0) {
			return new HashSet<>(LITERATURE_TYPE_VALUES);
		}
		return this.docTypes;
	}
	
	QueryBuilder singleCdtnQB(String key, String term, String type) throws ParseException {
		String value = term;
		if(StringUtils.isEmpty(value) || 
				!checkField(key, term))
			return QueryBuilders.boolQuery();
		String keyword = type.contains(OPRATE_EQUAL) ? ".keyword": "";
		
		return queryFieldBuilder(key, value, keyword);
	}
	
	QueryBuilder rangeQB(String key, String term, String type) throws ParseException{
		String value = term;
		if(StringUtils.isEmpty(value) || 
				!checkField(key, term))
			return QueryBuilders.boolQuery();
		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
		String fields = this.field_map.getOrDefault(key.toUpperCase(), "undefined");//如果未定义该字段，但查了该字段，什么也查不到
		for (String field : StringUtils.split(fields, ",")) {
			RangeQueryBuilder rangeBuilder = QueryBuilders.rangeQuery(field + ".keyword");
			switch (type) {
			case OPRATE_LESSTHAN:
				boolQueryBuilder.should(rangeBuilder.lt(value));
				break;
			case OPRATE_LESSTHANEQ:
				boolQueryBuilder.should(rangeBuilder.lte(value));
				break;
			case OPRATE_MORETHAN:
				boolQueryBuilder.should(rangeBuilder.gt(value));
				break;
			case OPRATE_MORETHANEQ:
				boolQueryBuilder.should(rangeBuilder.gte(value));
				break;

			default:
				break;
			}
		} 
		
		return boolQueryBuilder;
	}
	
	QueryBuilder queryFieldBuilder(String key, String value, String keyword) {
		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
		String fields = this.field_map.getOrDefault(key.toUpperCase(), "undefined");//如果未定义该字段，但查了该字段，什么也查不到
//		if(StringUtils.isBlank(fields))
//			return null;
		for(String string: value.split(" ")) {
			BoolQueryBuilder should = QueryBuilders.boolQuery();
			boolQueryBuilder.must().add(should);
			
			for (String v : string.split(",")) {
				for (String field : StringUtils.split(fields, ",")) {
					if(v.contains("?") || value.contains("*")) {
						should.should(QueryBuilders.wildcardQuery(field + ".keyword", v));
					}else {
						should.should(QueryBuilders.matchPhraseQuery(field + keyword, v));
					}
				} 
			}
		}
		
		return boolQueryBuilder;
	}
	
	QueryBuilder queryTypeBuilder(String key, String value, boolean isWildcard) {
		if(isWildcard) {
			return QueryBuilders.wildcardQuery(key, value);
		}else {
			return QueryBuilders.matchPhraseQuery(key, value);
		}
	}
	
	boolean checkField(String key, String value) throws ParseException {
		if(key.toUpperCase().equals("TY")) {
			for (String v : value.split(",| ")) {
				if(DOC_TYPE_VALUES.contains(v)) {
					types.add(v);
				}else {
					throw new ParseException("TY字段的值填写错误");
				}
			}
//			return false;
		}else if(key.toUpperCase().equals("DT")) {
			for (String v : value.split(",| ")) {
				if(LITERATURE_TYPE_VALUES.contains(v)) {
					docTypes.add(v);
				}else {
					throw new ParseException("DT字段的值填写错误");
				}
			}
//			return false;
		}else {
			if(!SEARCH_FIELDS.contains(key.toUpperCase()))
				throw new ParseException("字段"+ key +"未定义")  ;
		}
		return true;
	}
	
	
//	public List<String> getTypes(){
//		DOC_TYPE
//	}

//	QueryBuilder freeTextCdtn(String freeText) {
//		return QueryBuilders.boolQuery().should(QueryBuilders.matchPhraseQuery("@graph.chtTitle.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.chsTitle.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.chsCreator.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.chtCreator.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.prefaceAndPostscript.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.postilAndCollation.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.chsEdition.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.chtEdition.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.seriesDescription.@value", freeText))
//				.should(QueryBuilders.matchPhraseQuery("@graph.shelfMark.@value", freeText));
//	}
	
}
